package com.ruoyi.exam.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.github.pagehelper.PageHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;

import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.exam.domain.entity.TTask;
import com.ruoyi.exam.domain.entity.TTaskExamPaper;
import com.ruoyi.exam.domain.entity.TTaskExe;
import com.ruoyi.exam.domain.entity.Question;
import com.ruoyi.exam.mapper.TTaskExamPaperAnswerMapper;
import com.ruoyi.exam.mapper.TTaskExamPaperMapper;
import com.ruoyi.exam.mapper.TTaskExeMapper;
import com.ruoyi.exam.mapper.TTaskMapper;
import com.ruoyi.exam.mapper.QuestionMapper;
import com.ruoyi.exam.service.ITTaskExeService;
import com.ruoyi.exam.task.DailyTaskPaperGenerator;
import com.ruoyi.system.mapper.SysUserMapper;

/**
 * 任务执行列Service业务层处理
 * 
 * @author ruoyi
 * @date 2024-12-19
 */
@Service
public class TTaskExeServiceImpl implements ITTaskExeService {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    // 题目缓存，避免频繁全量查询
    private volatile List<Question> cachedQuestions = null;
    private volatile long cacheExpireTime = 0;
    private static final long CACHE_DURATION = 5 * 60 * 1000; // 5分钟缓存

    @Autowired
    private TTaskExeMapper tTaskExeMapper;

    @Autowired
    private TTaskExamPaperMapper tTaskExamPaperMapper;

    @Autowired
    private TTaskMapper tTaskMapper;

    @Autowired
    private TTaskExamPaperAnswerMapper tTaskExamPaperAnswerMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private DailyTaskPaperGenerator dailyTaskPaperGenerator;

    @Autowired
    private QuestionMapper questionMapper;

    /**
     * 查询任务执行列
     * 
     * @param id 任务执行列主键
     * @return 任务执行列
     */
    @Override
    public TTaskExe selectTTaskExeById(Long id) {
        TTaskExe selectTTaskExeById = tTaskExeMapper.selectTTaskExeById(id);
        TTaskExe param = new TTaskExe();
        param.setTaskId(selectTTaskExeById.getTaskId());
        List<TTaskExe> selectTTaskExeList = tTaskExeMapper.selectTTaskExeList(param);
        TTaskExe result = new TTaskExe();
        result.setUserIds(new ArrayList<>());
        result.setTaskId(selectTTaskExeById.getTaskId());
        result.setCompleteNum(0);
        result.setTotalNum(selectTTaskExeList.size());
        for (TTaskExe selectTTaskExeList2 : selectTTaskExeList) {
            result.setBindTime(selectTTaskExeList2.getBindTime());
            result.getUserIds().add(selectTTaskExeList2.getUserId());
            result.setCompleteNum(
                    selectTTaskExeList2.getTaskStatus() == 0 ? result.getCompleteNum() : result.getCompleteNum() + 1);
        }
        return result;
    }

    /**
     * 查询任务执行列列表
     * 
     * @param tTaskExe 任务执行列
     * @return 任务执行列
     */
    @Override
    public List<TTaskExe> selectTTaskExeList(TTaskExe tTaskExe) { // 合并一下，每个任务一条记录
        tTaskExe.setUserId(null); // 不通过用户ID过滤
        List<TTaskExe> selectTTaskExeList = tTaskExeMapper.selectTTaskExeList(tTaskExe);
        // 根据selectTTaskExeList内元素的taskid去重，并且合并相同taskid的userid到userIds，同时根据任务状态统计总任务数量和已完成的任务数量
        Map<Long, TTaskExe> map = new HashMap<>();

        // 收集所有需要查询的任务ID
        Set<Long> taskIds = selectTTaskExeList.stream()
                .map(TTaskExe::getTaskId)
                .collect(Collectors.toSet());

        // 批量查询任务信息
        List<TTask> tasks = new ArrayList<>();
        if (!taskIds.isEmpty()) {
            tasks = tTaskMapper.selectTTaskByIds(taskIds);
        }
        // List<TTask> tasks = tTaskMapper.selectTTaskByIds(taskIds);

        // 将任务信息转为Map便于快速查找
        Map<Long, TTask> taskMap = tasks.stream()
                .collect(Collectors.toMap(TTask::getId, task -> task));

        for (TTaskExe exe : selectTTaskExeList) {
            // 从Map中获取任务信息，避免重复查询
            exe.setTask(taskMap.get(exe.getTaskId()));

            if (map.containsKey(exe.getTaskId())) {
                TTaskExe tTaskExe2 = map.get(exe.getTaskId());
                tTaskExe2.setTaskStatus(exe.getTaskStatus());
                tTaskExe2.getUserIds().add(exe.getUserId());
                tTaskExe2.setTotalNum(tTaskExe2.getTotalNum() + 1);
                tTaskExe2.setCompleteNum(
                        tTaskExe2.getTaskStatus() == 0 ? tTaskExe2.getCompleteNum() : tTaskExe2.getCompleteNum() + 1);
            } else {
                exe.setUserIds(new ArrayList<>());
                exe.setTotalNum(1);
                exe.setCompleteNum(exe.getTaskStatus() == 0 ? 0 : 1);
                map.put(exe.getTaskId(), exe);
            }
        }
        // 将map.values()转成list并按bindTime倒序排序
        List<TTaskExe> resultList = new ArrayList<>(map.values());
        resultList.sort((a, b) -> b.getBindTime().compareTo(a.getBindTime()));
        return resultList;
    }

    /**
     * 新增任务执行列
     * 
     * @param tTaskExe 任务执行列
     * @return 结果
     */
    @Override
    @Transactional
    public int insertTTaskExe(TTaskExe tTaskExe) {
        // 用户ID列表转换
        if (StringUtils.isEmpty(tTaskExe.getUserIds())) {
            throw new RuntimeException("未选择用户");
        }
        // 查询库里是否已经包含了这个任务的执行记录
        TTaskExe param = new TTaskExe();
        param.setTaskId(tTaskExe.getTaskId());
        List<TTaskExe> tTaskExes = tTaskExeMapper.selectTTaskExeList(param);
        if (tTaskExes.size() > 0) {
            throw new RuntimeException("该任务已经有执行记录，不能重复执行");
        }
        Date now = DateUtils.getNowDate();
        List<TTaskExe> tTaskExesToDb = new ArrayList<>();
        for (Long userIds : tTaskExe.getUserIds()) {
            TTaskExe taskExeToDb = new TTaskExe();
            taskExeToDb.setTaskId(tTaskExe.getTaskId());
            taskExeToDb.setUserId(userIds);
            taskExeToDb.setBindTime(now);
            taskExeToDb.setTaskStatus(0l);
            taskExeToDb.setDeleted(0);
            tTaskExesToDb.add(taskExeToDb);
        }

        // 如果任务是每日一练，则需要在推动任务执行的时候生成试卷。因为每日一练的试卷是根据用户生成的，所以需要生成试卷
        // 调用生成试卷的接口
        logger.info("注册事务提交后调用生成试卷的接口");
        final Long taskId = tTaskExe.getTaskId();
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                logger.info("事务提交后执行生成试卷操作，任务ID: {}", taskId);
                dailyTaskPaperGenerator.generateDailyTaskPaperManually(taskId);
            }
        });

        int row = tTaskExeMapper.insertBatchTTaskExe(tTaskExesToDb);
        return row;
    }

    /**
     * 修改任务执行列
     * 
     * @param tTaskExe 任务执行列
     * @return 结果
     */
    @Override
    @Transactional
    public int updateTTaskExe(TTaskExe tTaskExe) {
        // 更新任务执行列表，对原本就存在的用户不进行变更，所以这里先查询数据库的用户列表，和参数进行对比，如果参数中没有，则删除，如果参数中有，则更新
        TTaskExe params = new TTaskExe();
        params.setTaskId(tTaskExe.getTaskId());
        List<TTaskExe> tTaskExes = tTaskExeMapper.selectTTaskExeList(params);

        // 用户ID列表转换
        // if (StringUtils.isEmpty(tTaskExe.getUserIds())) {
        // return 1;
        // }
        List<Long> newUserIds = tTaskExe.getUserIds();

        // 获取数据库中已存在的用户ID列表
        logger.info("获取数据库中已存在的用户ID列表");
        List<Long> existingUserIds = tTaskExes.stream()
                .map(TTaskExe::getUserId)
                .collect(Collectors.toList());
        logger.info("获取数据库中已存在的用户ID列表: {}", existingUserIds);
        // 1. 找出需要删除的用户(在数据库中存在但不在新列表中)
        logger.info("找出需要删除的用户");
        List<Long> toDeleteUserIds = existingUserIds.stream()
                .filter(id -> !newUserIds.contains(id))
                .collect(Collectors.toList());
        logger.info("需要删除的用户: {}", toDeleteUserIds);

        // 2. 找出需要新增的用户(在新列表中但不在数据库中)
        logger.info("找出需要新增的用户");
        List<Long> toInsertUserIds = newUserIds.stream()
                .filter(id -> !existingUserIds.contains(id))
                .collect(Collectors.toList());
        logger.info("需要新增的用户: {}", toInsertUserIds);

        // 3. 执行删除操作
        logger.info("执行删除操作");
        if (!toDeleteUserIds.isEmpty()) {
            for (Long userId : toDeleteUserIds) {
                TTaskExe deleteParams = new TTaskExe();
                deleteParams.setTaskId(tTaskExe.getTaskId());
                deleteParams.setUserId(userId);
                List<TTaskExe> toDelete = tTaskExeMapper.selectTTaskExeList(deleteParams);
                if (!toDelete.isEmpty()) {
                    tTaskExeMapper.deleteTTaskExeById(toDelete.get(0).getId());
                }
            }
        }

        // 4. 执行新增操作
        logger.info("执行新增操作");
        if (!toInsertUserIds.isEmpty()) {
            Date now = DateUtils.getNowDate();
            for (Long userId : toInsertUserIds) {
                TTaskExe newTaskExe = new TTaskExe();
                newTaskExe.setTaskId(tTaskExe.getTaskId());
                newTaskExe.setUserId(userId);
                newTaskExe.setBindTime(now);
                newTaskExe.setTaskStatus(0L);
                newTaskExe.setCreateTime(now);
                newTaskExe.setUpdateTime(now);
                tTaskExeMapper.insertTTaskExe(newTaskExe);
                logger.info("新增任务执行列: {}", newTaskExe);
            }
        }

        // 调用生成试卷的接口
        logger.info("注册事务提交后调用生成试卷的接口");
        final Long taskId = tTaskExe.getTaskId();
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                logger.info("事务提交后执行生成试卷操作，任务ID: {}", taskId);
                dailyTaskPaperGenerator.generateDailyTaskPaperManually(taskId);
            }
        });

        return 1;
    }

    /**
     * 批量删除任务执行列
     * 
     * @param ids 需要删除的任务执行列主键
     * @return 结果
     */
    @Override
    public int deleteTTaskExeByIds(Long[] ids) {
        int row = 0;
        for (Long ids2 : ids) {
            row = row + deleteTTaskExeById(ids2);
        }
        return row;
    }

    /**
     * 删除任务执行列信息
     * 
     * @param id 任务执行列主键
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteTTaskExeById(Long id) {
        // 根据taskId删除
        Long taskId = tTaskExeMapper.selectTTaskExeById(id).getTaskId();
        return tTaskExeMapper.deleteTTaskExeByTaskId(taskId);
    }

    @Override
    public List<TTaskExe> selectTTaskExeListByTaskId(Long taskId) {
        TTaskExe param = new TTaskExe();
        param.setTaskId(taskId);
        List<TTaskExe> selectTTaskExeList = tTaskExeMapper.selectTTaskExeList(param);
        // for循环遍历selectTTaskExeList，填充用户信息
        for (TTaskExe exe : selectTTaskExeList) {
            exe.setSysUser(sysUserMapper.selectUserById(exe.getUserId()));
        }
        return selectTTaskExeList;
    }

    @Override
    // @DataScope(deptAlias = "sd")
    public List<TTaskExe> selectTTaskExeDetailList(TTaskExe tTaskExe) {
        List<TTaskExe> selectTTaskExeList = tTaskExeMapper.selectTTaskExeList(tTaskExe);
        // 收集所有需要查询的任务ID
        Set<Long> taskIds = selectTTaskExeList.stream()
                .map(TTaskExe::getTaskId)
                .collect(Collectors.toSet());

        // 批量查询任务信息9
        List<TTask> tasks = new ArrayList<>();
        if (!taskIds.isEmpty()) {
            tasks = tTaskMapper.selectTTaskByIds(taskIds);
        }

        // 将任务信息转为Map便于快速查找
        Map<Long, TTask> taskMap = tasks.stream()
                .collect(Collectors.toMap(TTask::getId, task -> task));

        // for循环遍历selectTTaskExeList，填充TTask信息
        for (TTaskExe exe : selectTTaskExeList) {
            exe.setTask(taskMap.get(exe.getTaskId()));

            // 判断任务是否过期
            if (exe.getTask() != null && exe.getTask().getEndTime() != null) {
                // 获取当前日期（不含时分秒）
                Date today = DateUtils.parseDate(DateUtils.getDate());
                // 获取任务结束日期（不含时分秒）
                Date endDate = DateUtils
                        .parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, exe.getTask().getEndTime()));
                // 如果结束日期小于今天，则为过期任务
                exe.getTask().setExpire(endDate.before(today));
            }

            /**
             * 填充试卷
             * 如果是每日一练任务，则需要从t_task_exe表的id和task_id关联到t_task_exam_paper表的task_exe_id和task_id，获取一对一的试卷信息
             * 如果是普通任务，因为普通任务创建的时候就绑定好了试卷，则直接t_task_exe的任务task_id关联到t_task_exam_paper表，获取试卷信息即可
             * 
             */
            if (exe.getTask() != null && exe.getTask().getId() != null) {
                if (exe.getTask().getType() == 1) {
                    TTaskExamPaper tTaskExamPaper = new TTaskExamPaper();
                    tTaskExamPaper.setTaskId(exe.getTask().getId());
                    tTaskExamPaper.setTaskExeId(exe.getId());
                    List<TTaskExamPaper> selectTTaskExamPaperList = tTaskExamPaperMapper
                            .selectTTaskExamPaperList(tTaskExamPaper);
                    if (StringUtils.isNotEmpty(selectTTaskExamPaperList)) {
                        TTaskExamPaper paper = selectTTaskExamPaperList.get(0);
                        // 检查并修复试卷中的空选项数据
                        fixEmptyQuestionOptions(paper);
                        exe.getTask().settTaskExamPaper(paper);
                    }
                } else {
                    TTaskExamPaper tTaskExamPaper = new TTaskExamPaper();
                    tTaskExamPaper.setTaskId(exe.getTask().getId());
                    List<TTaskExamPaper> selectTTaskExamPaperList = tTaskExamPaperMapper
                            .selectTTaskExamPaperList(tTaskExamPaper);
                    if (StringUtils.isNotEmpty(selectTTaskExamPaperList)) {
                        TTaskExamPaper paper = selectTTaskExamPaperList.get(0);
                        // 检查并修复试卷中的空选项数据
                        fixEmptyQuestionOptions(paper);
                        exe.getTask().settTaskExamPaper(paper);
                    }
                }
            }
            // 填充答卷
            if (exe.getTaskExamPaperAnswerId() != null) {
                exe.setTaskExamPaperAnswer(tTaskExamPaperAnswerMapper.selectTTaskExamPaperAnswerById(
                        exe.getTaskExamPaperAnswerId()));
            }
        }
        return selectTTaskExeList;
    }

    /**
     * 检查并修复试卷中的空选项数据
     * 如果发现题目选项为空，通过题目标题从t_question表查询并修复
     */
    private void fixEmptyQuestionOptions(TTaskExamPaper paper) {
        if (paper == null || StringUtils.isEmpty(paper.getPaperContent())) {
            return;
        }

        try {
            // 解析试卷内容
            JSONObject paperJson = JSON.parseObject(paper.getPaperContent());
            JSONArray questionsArray = paperJson.getJSONArray("examPaperQuestions");
            
            if (questionsArray == null || questionsArray.isEmpty()) {
                return;
            }

            boolean isUpdated = false;
            
            // 遍历试卷中的题目
            for (int i = 0; i < questionsArray.size(); i++) {
                JSONObject questionJson = questionsArray.getJSONObject(i);
                String questionText = questionJson.getString("questionText");
                String questionTitle = questionJson.getString("questionTitle");
                
                // 检查是否为空选项数据
                if (StringUtils.isEmpty(questionText) || "[]".equals(questionText) || "\"\"".equals(questionText)) {
                    logger.info("发现空选项题目，题干：{}", questionTitle);
                    
                    // 规范化题目标题，去除多余空格
                    String normalizedTitle = normalizeQuestionTitle(questionTitle);
                    
                    // 通过题目标题查询正确的选项数据
                    Question queryParam = new Question();
                    queryParam.setQuestionTitle(normalizedTitle);
                    List<Question> questions = questionMapper.selectQuestionList(queryParam);
                    
                    // 如果精确匹配未找到，尝试使用模糊匹配
                    if (questions.isEmpty() && StringUtils.isNotEmpty(normalizedTitle)) {
                        questions = findQuestionByFuzzyTitle(normalizedTitle);
                    }
                    
                    if (!questions.isEmpty()) {
                        Question correctQuestion = questions.get(0);
                        if (StringUtils.isNotEmpty(correctQuestion.getQuestionText()) && 
                            !"[]".equals(correctQuestion.getQuestionText())) {
                            
                            // 更新试卷中的题目选项
                            questionJson.put("questionText", correctQuestion.getQuestionText());
                            isUpdated = true;
                            logger.info("已修复题目选项，题干：{}，选项：{}", questionTitle, correctQuestion.getQuestionText());
                        }
                    } else {
                        logger.warn("未找到匹配的题目，原题干：{}，规范化题干：{}", questionTitle, normalizedTitle);
                    }
                }
            }
            
            // 如果有更新，保存到数据库
            if (isUpdated) {
                paper.setPaperContent(JSON.toJSONString(paperJson));
                tTaskExamPaperMapper.updateTTaskExamPaper(paper);
                logger.info("已更新试卷数据，试卷ID：{}", paper.getId());
            }
            
        } catch (Exception e) {
            logger.error("修复试卷选项数据时发生异常：{}", e.getMessage(), e);
        }
    }

    /**
     * 规范化题目标题，去除多余空格和特殊字符
     */
    private String normalizeQuestionTitle(String title) {
        if (StringUtils.isEmpty(title)) {
            return title;
        }
        
        // 去除首尾空格，将连续的空白字符替换为单个空格
        return title.trim().replaceAll("\\s+", " ");
    }

    /**
     * 通过模糊匹配查找题目
     * 使用内存缓存，5分钟过期，避免频繁全量查询数据库
     */
    private List<Question> findQuestionByFuzzyTitle(String normalizedTitle) {
        try {
            // 获取缓存的题目列表
            List<Question> allQuestions = getCachedQuestions();
            
            return allQuestions.stream()
                .filter(q -> {
                    String dbTitle = normalizeQuestionTitle(q.getQuestionTitle());
                    return normalizedTitle.equals(dbTitle);
                })
                .collect(Collectors.toList());
                
        } catch (Exception e) {
            logger.error("模糊匹配题目时发生异常：{}", e.getMessage(), e);
            return new ArrayList<>();
        }
    }

    /**
     * 获取缓存的题目列表，缓存5分钟
     */
    private List<Question> getCachedQuestions() {
        long currentTime = System.currentTimeMillis();
        
        // 如果缓存为空或已过期，重新加载
        if (cachedQuestions == null || currentTime > cacheExpireTime) {
            synchronized (this) {
                // 双重检查，避免并发重复加载
                if (cachedQuestions == null || currentTime > cacheExpireTime) {
                    logger.info("题目缓存已过期，重新加载题目数据");
                    cachedQuestions = questionMapper.selectQuestionList(new Question());
                    cacheExpireTime = currentTime + CACHE_DURATION;
                    logger.info("题目缓存已更新，共加载{}条题目，缓存将在{}分钟后过期", 
                              cachedQuestions.size(), CACHE_DURATION / 60000);
                }
            }
        }
        
        return cachedQuestions;
    }
}
